package com.bcx.wind.workflow.access;

import com.bcx.wind.workflow.access.paging.Paging;
import com.bcx.wind.workflow.entity.WindActHistory;
import com.bcx.wind.workflow.entity.WindTaskActor;
import com.bcx.wind.workflow.support.ObjectHelper;
import com.bcx.wind.workflow.support.TimeHelper;

import java.sql.Timestamp;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import static com.bcx.wind.workflow.access.AccessSqlConstant.*;


/**
 * 工作流持久层处理工具
 *
 * @author zhanglei
 */
public abstract class AbstractAccessSupport implements Access{

    /**
     * 分页插件
     */
    protected Paging paging;


    /**
     * 拼接数组类型参数 sql
     *
     * @param sql  sql语句
     * @param ids  数组参数
     * @param pro  属性
     * @param args 拼接后sql，所需要的参数
     */
    void  buildIdsSql(LinkedList<Object> args,StringBuilder sql,List<String> ids,String pro){
        if(ObjectHelper.isEmpty(ids)){
            return ;
        }
        sql.append(SPACE)
                .append(pro)
                .append(IN)
                .append(LEFT_BRACK);

        for(int i=0 ; i<ids.size() ; i++){
            if(i < ids.size()-1) {
                sql.append(SPACE)
                        .append(ASK_CHAR)
                        .append(COMMA);
                args.addLast(ids.get(i));
                continue;
            }
            sql.append(SPACE).append(ASK_CHAR);
            args.addLast(ids.get(i));
        }
        sql.append(RIGHT_BRACK);
    }


    /**
     * 构造查询流程定义数据查询条件，以及sql语句
     *
     * @param sql       待拼接的sql语句
     * @param filter    过滤条件
     * @param page       分页参数
     * @return           查询条件
     */
    List<Object> buildProcessQuery(StringBuilder sql,QueryFilter filter,WindPage page,int type){
        //查询参数
        LinkedList<Object> args = new LinkedList<>();
        sql.append(PLACE);
        if(filter != null){
            String processId = filter.getProcessId();
            if(processId != null){
                sql.append(AND).append(ID)
                        .append(VAR);
                args.addLast(processId);
            }

            String processName = filter.getProcessName();
            if(processName != null){
                sql.append(AND).append(PROCESS_NAME)
                        .append(VAR);
                args.addLast(processName);
            }

            String status = filter.getStatus();
            if(status != null){
                sql.append(AND).append(STATUS)
                        .append(VAR);
                args.addLast(status);
            }

            Integer version = filter.getVersion();
            if(version != null && version != 0){
                sql.append(AND).append(VERSION)
                        .append(VAR);
                args.addLast(version);
            }

            String parentId = filter.getParentId();
            if(parentId != null){
                sql.append(AND).append(PARENT_ID)
                        .append(VAR);
                args.addLast(parentId);
            }

            String module = filter.getProcessModule();
            if(module != null){
                sql.append(AND).append(MODULE)
                        .append(VAR);
                args.addLast(module);
            }

            //时间查询
            buildBetweenCreateTimeQuery(args,sql,filter);

        }

        if(type ==  QUERY_TYPE){
           buildOrderBySql(sql,filter);
        }

        //分页
        if(page != null) {
            paging.buildSql(sql, page);
        }
        return args;
    }

    /**
     * 构造历史实例查询语句  查询参数
     *
     * @param sql     查询sql语句
     * @param filter  过滤条件
     * @param page     分页条件
     * @return         查询参数
     * @param type     查询类型
     */
    List<Object>  buildHistoryQuery(StringBuilder sql,QueryFilter filter,WindPage page,int type){
        LinkedList<Object> args = new LinkedList<>();
        sql.append(PLACE);

        if(filter != null) {
            String taskId = filter.getTaskId();
            if (taskId != null) {
                sql.append(AND)
                        .append(TASK_ID)
                        .append(VAR);
                args.addLast(taskId);
            }

            String taskName = filter.getTaskName();
            if (taskName != null) {
                sql.append(AND)
                        .append(TASK_NAME)
                        .append(VAR);
                args.addLast(taskName);
            }

            String processId = filter.getProcessId();
            if (processId != null) {
                sql.append(AND)
                        .append(PROCESS_ID)
                        .append(VAR);
                args.addLast(processId);
            }

            String orderId = filter.getOrderId();
            if (orderId != null) {
                sql.append(AND)
                        .append(ORDER_ID)
                        .append(VAR);
                args.addLast(orderId);
            }

            String processName = filter.getProcessName();
            if (processName != null) {
                sql.append(AND)
                        .append(PROCESS_NAME)
                        .append(VAR);
                args.addLast(processName);
            }

            String[] actorIds = filter.getTaskActorId();
            if (!ObjectHelper.isEmpty(actorIds)) {
                List<String> ids = Arrays.asList(actorIds);
                sql.append(AND);
                buildIdsSql(args, sql, ids, ACTOR_ID);
            }

            String taskType = filter.getTaskType();
            if(taskType != null){
                sql.append(AND)
                        .append(TASK_TYPE)
                        .append(VAR);
                args.addLast(taskType);
            }

            String system = filter.getSystem();
            if(system != null){
                sql.append(AND)
                        .append(SYSTEM)
                        .append(VAR);
                args.addLast(system);
            }

            buildBetweenCreateTimeQuery(args,sql,filter);;
        }

        if(type ==  QUERY_TYPE){
            buildOrderBySql(sql,filter);
        }

        if(page != null){
            paging.buildSql(sql,page);
        }
        return args;
    }



    /**
     * 构建流程实例查询参数  查询语句
     *
     * @param sql       sql语句
     * @param filter    过滤条件
     * @param page       分页条件
     * @return           查询参数
     */
    List<Object> buildOrderQuery(StringBuilder sql,QueryFilter filter ,WindPage page, int type){
        LinkedList<Object> args = new LinkedList<>();
        sql.append(PLACE);

        if(filter != null) {
            String processId = filter.getProcessId();
            if (processId != null) {
                sql.append(AND)
                        .append(PROCESS_ID)
                        .append(VAR);
                args.addLast(processId);
            }

            String businessId = filter.getBusinessId();
            if(businessId != null){
                sql.append(AND)
                        .append(BUSINESS_ID)
                        .append(VAR);
                args.addLast(businessId);
            }

            List<String> businessIds = filter.getBusinessIds();
            if(!ObjectHelper.isEmpty(businessIds)){
                buildIdsSql(args,sql,businessIds,BUSINESS_ID);
            }

            String status = filter.getStatus();
            if (status != null) {
                sql.append(AND)
                        .append(STATUS)
                        .append(VAR);
                args.addLast(status);
            }

            String createUser = filter.getCreateUser();
            if (createUser != null) {
                sql.append(AND)
                        .append(CREATE_USER)
                        .append(VAR);
                args.addLast(createUser);
            }

            String parentId = filter.getParentId();
            if (parentId != null) {
                sql.append(AND)
                        .append(PARENT_ID)
                        .append(VAR);
                args.addLast(parentId);
            }

            String orderType = filter.getOrderType();
            if(orderType != null){
                sql.append(AND).append(ORDER_TYPE)
                        .append(VAR);
                args.addLast(orderType);
            }


            String system = filter.getSystem();
            if (system != null) {
                sql.append(AND)
                        .append(SYSTEM)
                        .append(VAR);
                args.addLast(system);
            }

            if (filter.isOverTime()) {
                sql.append(AND)
                        .append(EXPIRE_TIME)
                        .append(LESS_THAN)
                        .append(ASK_CHAR);
                args.addLast(TimeHelper.nowDate());
            }

            String[] orderIds = filter.getOrderIds();
            if(!ObjectHelper.isEmpty(orderIds)){
                List<String> ids = Arrays.asList(orderIds);
                buildIdsSql(args,sql,ids,ID);
            }

            buildBetweenCreateTimeQuery(args,sql,filter);

        }

        if(type ==  QUERY_TYPE){
            buildOrderBySql(sql,filter);
        }

        if(page != null){
            paging.buildSql(sql,page);
        }
        return args;
    }


    /**
     * 构建流程配置查询条件  查询sql
     *
     * @param sql      sql查询语句
     * @param filter   过滤条件
     * @return          sql参数
     */
    List<Object>  buildConfigQuery(StringBuilder sql,QueryFilter filter,int type){
        LinkedList<Object> args = new LinkedList<>();
        sql.append(PLACE);

        if(filter != null) {
            String processId = filter.getProcessId();
            if (processId != null) {
                sql.append(AND)
                        .append(PROCESS_ID)
                        .append(VAR);
                args.addLast(processId);
            }

            String processName = filter.getProcessName();
            if (processName != null) {
                sql.append(AND)
                        .append(PROCESS_NAME)
                        .append(VAR);
                args.addLast(processName);
            }

            String nodeId = filter.getNodeId();
            if (nodeId != null) {
                sql.append(AND)
                        .append(NODE_ID)
                        .append(VAR);
                args.addLast(nodeId);
            }

            buildBetweenCreateTimeQuery(args,sql,filter);


        }
        if(type ==  QUERY_TYPE){
            buildOrderBySql(sql,filter);
        }
        return args;
    }


    /**
     * 构建任务审批人查询语句 查询条件
     *
     * @param sql     sql语句
     * @param filter  过滤条件
     * @return        sql参数
     */
    LinkedList<Object> buildTaskActorQuery(StringBuilder sql,QueryFilter filter){
        LinkedList<Object>  args = new LinkedList<>();
        sql.append(PLACE);

        if(filter != null) {
            String taskId = filter.getTaskId();
            if (taskId != null) {
                sql.append(AND)
                        .append(TASK_ID)
                        .append(VAR);
                args.addLast(taskId);
            }

            String[] taskIds = filter.getTaskIds();
            if(!ObjectHelper.isEmpty(taskIds)){
                sql.append(AND);
                List<String> ids = Arrays.asList(taskIds);
                buildIdsSql(args,sql,ids,TASK_ID);
            }

            String[] actorIds = filter.getTaskActorId();
            if (!ObjectHelper.isEmpty(actorIds)) {
                sql.append(AND);
                List<String> ids = Arrays.asList(actorIds);
                buildIdsSql(args, sql, ids, ACTOR_ID);
            }
        }

        return args;
    }


    /**
     * 构建任务查询语句   查询参数
     *
     * @param sql     sql语句
     * @param filter  过滤条件
     * @param page    分页条件
     * @return        查询参数
     */
    LinkedList<Object>  buildTaskQuery(StringBuilder sql,QueryFilter filter,WindPage page,int type){
        LinkedList<Object> args = new LinkedList<>();

        if(filter != null){
            String[] actorIds = filter.getTaskActorId();
            if(!ObjectHelper.isEmpty(actorIds)){
                sql.append(" task, wind_task_actor actor where task.id = actor.task_id and ");
                List<String> ids = Arrays.asList(actorIds);
                buildIdsSql(args,sql,ids,ACTOR_ID);
            }else{
                sql.append(" where 1=1 ");
            }

            String taskName = filter.getTaskName();
            if(taskName != null){
                sql.append(AND)
                        .append(TASK_NAME)
                        .append(VAR);
                args.addLast(taskName);
            }

            String taskType = filter.getTaskType();
            if(taskType != null){
                sql.append(AND)
                        .append(TASK_TYPE)
                        .append(VAR);
                args.addLast(taskType);
            }

            String status = filter.getStatus();
            if(status != null){
                sql.append(AND)
                        .append(STATUS)
                        .append(VAR);
                args.addLast(status);
            }

            String orderId = filter.getOrderId();
            if(orderId != null){
                sql.append(AND)
                        .append(ORDER_ID)
                        .append(VAR);
                args.addLast(orderId);
            }

            String processId = filter.getProcessId();
            if(processId != null){
                sql.append(AND)
                        .append(PROCESS_ID)
                        .append(VAR);
                args.addLast(processId);
            }

            String position = filter.getPosition();
            if(position != null){
                sql.append(AND)
                        .append(POSITION)
                        .append(VAR);
                args.addLast(position);
            }

            String parentId = filter.getParentId();
            if(parentId != null){
                sql.append(AND)
                        .append(PARENT_ID)
                        .append(VAR);
                args.addLast(parentId);
            }

            String level = filter.getTaskLevel();
            if(!ObjectHelper.isEmpty(level)){
                sql.append(AND)
                        .append(TASK_LEVEL)
                        .append(VAR);
                args.addLast(level);
            }

            String[] orderIds = filter.getOrderIds();
            if(!ObjectHelper.isEmpty(orderIds)){
                sql.append(AND);
                List<String> ids = Arrays.asList(orderIds);
                buildIdsSql(args,sql,ids,ORDER_ID);
            }

            String[] taskIds=  filter.getTaskIds();
            if(!ObjectHelper.isEmpty(taskIds)){
                sql.append(AND);
                List<String> ids = Arrays.asList(taskIds);
                buildIdsSql(args,sql,ids,ID);
            }

            if(filter.isOverTime()){
                sql.append(AND)
                        .append(EXPIRE_TIME)
                        .append(LESS_THAN)
                        .append(ASK_CHAR);
                args.addLast(TimeHelper.nowDate());
            }

            buildBetweenCreateTimeQuery(args,sql,filter);
        }

        if(type ==  QUERY_TYPE){
            buildOrderBySql(sql,filter);
        }
        if(page != null){
            paging.buildSql(sql,page);
        }
        return args;
    }


    List<Object> buildRevokeQuery(StringBuilder sql,QueryFilter filter){
        LinkedList<Object> args = new LinkedList<>();
        sql.append(PLACE);

        if(filter != null){
            String orderId = filter.getOrderId();
            if(orderId != null){
                sql.append(AND)
                        .append(ORDER_ID)
                        .append(VAR);
                args.addLast(orderId);
            }

            String processId = filter.getProcessId();
            if(processId != null){
                sql.append(AND)
                        .append(PROCESS_ID)
                        .append(VAR);
                args.addLast(processId);
            }

            String taskName = filter.getTaskName();
            if(taskName != null){
                sql.append(AND)
                        .append(TASK_NAME)
                        .append(VAR);
                args.addLast(taskName);
            }

            //排序
            sql.append(ORDER_BY)
                    .append(CREATE_TIME)
                    .append(DESC);

        }

        return args;
    }


    private void buildBetweenCreateTimeQuery(LinkedList<Object> args,StringBuilder builder,QueryFilter filter){
        Timestamp startTime = filter.getCreateTimeStart();
        Timestamp endTime = filter.getCreateTimeEnd();
        if(startTime == null && endTime == null){
             return;
        }
        if(startTime != null && endTime == null){
            builder.append(AND)
                    .append(CREATE_TIME)
                    .append(GREATER_THAN)
                    .append(ASK_CHAR);
            args.addLast(startTime);
        }

        if(endTime != null && startTime == null){
            builder.append(AND)
                    .append(CREATE_TIME)
                    .append(LESS_THAN)
                    .append(ASK_CHAR);
            args.addLast(endTime);
        }

        if(startTime != null && endTime != null){
            builder.append(AND)
                    .append(CREATE_TIME)
                    .append(BETWEEN);
            args.addLast(startTime);
            args.addLast(endTime);
        }
    }

    /**
     * 构造批量新增完成历史履历记录
     *
     * @param histories   执行历史履历记录集合
     * @param sql          sql语句
     * @return             执行批量新增参数
     */
    List<Object>  insertListCompleteHistory(List<WindActHistory> histories,StringBuilder sql){
        LinkedList<Object> args = new LinkedList<>();

        for(int i=0 ; i<histories.size() ; i++){
            WindActHistory history = histories.get(i);
            if(i < histories.size()-1) {
                addHistory(history,args);
                sql.append(" (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?), ");
                continue;
            }
            addHistory(history,args);
            sql.append(" (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ");
        }
        return args;
    }


    List<Object>  insertListActors(List<WindTaskActor> windTaskActors,StringBuilder sql){
        LinkedList<Object> args = new LinkedList<>();

        for(int i=0 ; i<windTaskActors.size() ; i++){
            WindTaskActor actor = windTaskActors.get(i);
            if(i < windTaskActors.size() - 1){
                args.addLast(actor.getTaskId());
                args.addLast(actor.getActorId());
                sql.append(" (?,?), ");
                continue;
            }
            args.addLast(actor.getTaskId());
            args.addLast(actor.getActorId());
            sql.append(" (?,?) ");
        }
        return args;
    }

    private void addHistory(WindActHistory history, LinkedList<Object> args){
        args.addLast(history.getId());
        args.addLast(history.getTaskId());
        args.addLast(history.getTaskName());
        args.addLast(history.getTaskDisplayName());
        args.addLast(history.getProcessId());
        args.addLast(history.getOrderId());
        args.addLast(history.getProcessName());
        args.addLast(history.getProcessDisplayName());
        args.addLast(history.getOperate());
        args.addLast(history.getSuggest());
        args.addLast(history.getApproveTime());
        args.addLast(history.getActorId());
        args.addLast(history.getActorName());
        args.addLast(history.getCreateTime());
        args.addLast(history.getApproveUserVariable());
        args.addLast(history.getTaskType());
        args.addLast(history.getSystem());
        args.addLast(history.getSubmitUserVariable());
        args.addLast(history.getVariable());
        args.addLast(history.getTaskCreateUser());
        args.addLast(history.getTaskLevel());
        args.addLast(history.getTaskParentId());
    }


    /**
     * 构建任务实例查询sql语句
     *
     * @param sql       sql语句模板
     * @param filter    过滤条件
     * @param windPage  分页条件
     */
    List<Object>  buildQueryTaskInstanceSql(StringBuilder sql,TaskFilter filter,WindPage windPage,int type){
        LinkedList<Object> args = new LinkedList<>();
        sql.append(PLACE);

        if (!ObjectHelper.isEmpty(filter)) {

            String  processId = filter.getProcessId();
            if(!ObjectHelper.isEmpty(processId)){
                sql.append(AND)
                        .append(" task."+PROCESS_ID)
                        .append(VAR);
                args.addLast(processId);
            }

            String processName = filter.getProcessName();
            if(!ObjectHelper.isEmpty(processName)){
                sql.append(AND)
                        .append(PROCESS_NAME)
                        .append(VAR);
                args.addLast(processName);
            }

            String actor = filter.getActor();
            if(!ObjectHelper.isEmpty(actor)){
                sql.append(AND)
                        .append(ACTOR_ID)
                        .append(VAR);
                args.addLast(actor);
            }

            String orderId = filter.getOrderId();
            if(!ObjectHelper.isEmpty(orderId)){
                sql.append(AND)
                        .append(ORDER_ID)
                        .append(VAR);
                args.addLast(orderId);
            }

            String taskId = filter.getTaskId();
            if (!ObjectHelper.isEmpty(taskId)) {
                sql.append(AND)
                        .append(" actor."+TASK_ID)
                        .append(VAR);
                args.addLast(taskId);
            }

            String level = filter.getTaskLevel();
            if(!ObjectHelper.isEmpty(level)){
                sql.append(AND)
                        .append(TASK_TYPE)
                        .append(VAR);
                args.addLast(level);
            }

        }

        //时间排序
        if(type == QUERY_TYPE && filter.isOrderBy()) {
            sql.append(ORDER_BY)
                    .append(TASK_CREATE_TIME)
                    .append(DESC);
        }

        //分页操作
        if(windPage != null){
            this.paging.buildSql(sql,windPage);
        }
        return args;
    }


    /**
     * 构造 时间排序sql
     *
     * @param sql      sql语句
     * @param filter   过滤条件
     */
    private void  buildOrderBySql(StringBuilder sql,QueryFilter filter){
        if(filter != null) {
            String orderBy = filter.getOrderBy();
            orderBy = orderBy == null ? " desc " : " ";
            sql.append(ORDER_BY)
                    .append(CREATE_TIME)
                    .append(orderBy);
        }
    }
}
